package com.lzk.jetpacktest.update

import android.annotation.SuppressLint
import android.annotation.TargetApi
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.content.Context.NOTIFICATION_SERVICE
import android.content.Intent
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.core.content.FileProvider
import com.blankj.utilcode.util.UriUtils
import com.lzk.jetpacktest.MainApp
import com.lzk.jetpacktest.R
import kotlinx.coroutines.Job
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import rxhttp.toDownload
import rxhttp.wrapper.param.RxHttp
import java.io.File
import java.lang.Exception

/**
 * @Author: LiaoZhongKai
 * @Date: 2021/8/9 16:03
 * @Description: App版本更新
 */
class AppUpdateUtils private constructor(){

    private val mainScope = MainScope()
    private val mChannelId = "version_update"
    private val mNotificationId = 1
    private var mNotificationManager: NotificationManager? = null

    private var mContext: Context = MainApp.getInstance().getContext()
    private var mApkPath: String? = null
    private var mJob: Job? = null
    private var mDownloading: Boolean = false

    companion object{

        @SuppressLint("StaticFieldLeak")
        private var mSingleton: AppUpdateUtils? = null
        get() {
            if (field == null){
                field = AppUpdateUtils()
            }
            return field
        }

        @Synchronized
        fun getInstance(): AppUpdateUtils {
            return mSingleton!!
        }
    }

    private fun initNotification(){
        mNotificationManager = mContext.getSystemService(NOTIFICATION_SERVICE) as? NotificationManager
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
            createNotificationChannel()
        }
    }

    @TargetApi(Build.VERSION_CODES.O)
    private fun createNotificationChannel(){
        val channel = NotificationChannel(mChannelId,"版本更新",NotificationManager.IMPORTANCE_DEFAULT)
        mNotificationManager?.createNotificationChannel(channel)
    }

    private fun createFile(fileName: String): File?{
        try {
            val file = File(mContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),fileName)
            if (file.exists()){
                file.delete()
            }
            file.createNewFile()
            mApkPath = file.absolutePath
            return file
        }catch (e: Exception){
            e.printStackTrace()
        }
        return null
    }

    private fun sendProgressNotification(progress: Int){
        val notification = NotificationCompat.Builder(mContext, mChannelId)
            .setContentTitle("版本更新")
            .setContentText(if (progress == 100) "下载完成" else "下载中 $progress %")
            .setWhen(System.currentTimeMillis())
            .setSmallIcon(R.mipmap.ic_launcher_round)
            .setLargeIcon(BitmapFactory.decodeResource(mContext.resources, R.mipmap.ic_launcher))
            .setAutoCancel(true)
            .setProgress(100,progress,false)
            .build()
        mNotificationManager?.notify(mNotificationId,notification)
    }

    private fun sendFailedNotification(){
        val notification = NotificationCompat.Builder(mContext, mChannelId)
            .setContentTitle("版本更新")
            .setContentText("下载失败")
            .setWhen(System.currentTimeMillis())
            .setSmallIcon(R.mipmap.ic_launcher_round)
            .setLargeIcon(BitmapFactory.decodeResource(mContext.resources, R.mipmap.ic_launcher))
            .setAutoCancel(true)
            .build()
        mNotificationManager?.notify(mNotificationId,notification)
    }

    /**
     * 下载APK
     * [link] 下载链接
     * [fileName] APK文件名
     */
    fun downloadApk(link: String,fileName: String){
        if (mDownloading){
            return
        }
        initNotification()
        val filePath = createFile(fileName)?.absolutePath
        filePath?.let { destPath ->
            mJob = mainScope.launch {
                try {
                    mDownloading = true
                    sendProgressNotification(0)
                    mApkPath = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q){
                        val uri = RxHttp.get(link)
                            .toDownload(Android10DownloadFactory(mContext,destPath)){ progress ->
                                sendProgressNotification(progress.progress)
                            }.await()
                        UriUtils.uri2File(uri).absolutePath
                    }else{
                        val path = RxHttp.get(link)
                            .toDownload(destPath){ progress ->
                                sendProgressNotification(progress.progress)
                            }.await()
                        path
                    }
                    installApk()
                    mDownloading = false
                }catch (e: Exception){
                    e.printStackTrace()
                    sendFailedNotification()
                    mJob?.cancel()
                    mDownloading = false
                }
            }
        }
    }

    private fun installApk(){
        mApkPath?.let { path ->
            val intent = Intent(Intent.ACTION_VIEW).apply {
                flags = Intent.FLAG_ACTIVITY_NEW_TASK
            }
            if (Build.VERSION.SDK_INT >= 24){
                val file = File(path)
                val apkUri = FileProvider.getUriForFile(mContext,"com.lzk.jetpacktest.update.MyFileProvider",file)
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                intent.setDataAndType(apkUri, "application/vnd.android.package-archive")
            }else{
                intent.setDataAndType(
                    Uri.fromFile(File(path)),
                    "application/vnd.android.package-archive"
                )
            }
            mContext.startActivity(intent)
        }
    }

}